﻿// <copyright file="Operator.cs" company="Signal Processing Lab, Wuhan University">
// Copyright (c) 2009-2010 All Right Reserved
// </copyright>
// <author>Xinping Deng</author>
// <email>dentoby@gmail.com</email>
// <date>2010-4</date>
// <summary>This is part of Image.NET project.</summary>

namespace SPLWHU.Core.Raster
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Provides operator such as addition, subtract, multiply and division for values, arrays and matrices of different types.
    /// </summary>
    public class Operator
    {
        /// <summary>
        /// The created <see cref="DynamicCode"/>.
        /// </summary>
        private static Dictionary<string, DynamicCode> dynamicCodeHash = new Dictionary<string, DynamicCode>();

        /// <summary>
        /// Gets the specified <see cref="DynamicCode"/>.
        /// </summary>
        /// <param name="hashString">The hash string.</param>
        /// <returns>The dynamic code.</returns>
        public static DynamicCode Hash(string hashString)
        {
            if (!dynamicCodeHash.ContainsKey(hashString))
            {
                return null;
            }

            return dynamicCodeHash[hashString];
        }

        #region Negativation

        /// <summary>
        /// Computes the negativatin of an input.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="operand">The operand.</param>
        /// <returns>The result of negativation operator.</returns>
        public static TResult Negative<TInput, TResult>(TInput operand)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput).ToString();
            string type1 = typeof(TResult).ToString();
            string hashString = "NegativeValue.<" + type0 + ">.<" + type1 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T1 valOut = (T1)(-valInp);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1 }, "T0 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand);
        }

        /// <summary>
        /// Computes the negativatin of an input.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="operand">The operand.</param>
        /// <returns>The result of negativation operator.</returns>
        public static TResult[] Negative<TInput, TResult>(TInput[] operand)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput).ToString();
            string type1 = typeof(TResult).ToString();
            string hashString = "NegativeArray.<" + type0 + ">.<" + type1 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T1[] arrOut = new T1[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T1)(-arrInp[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1 }, "T0 arrInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand);
        }

        #endregion

        #region Addition

        /// <summary>
        /// Computes the addition of two inputs.
        /// </summary>
        /// <typeparam name="TInput0">The type of the input0.</typeparam>
        /// <typeparam name="TInput1">The type of the input1.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of addition operator.</returns>
        public static TResult Addition<TInput0, TInput1, TResult>(TInput0 operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "AdditionValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T2 valOut = (T2)(valInp1 + valInp2);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp1, T1 valInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the addition of two inputs.
        /// </summary>
        /// <typeparam name="TInput0">The type of the input0.</typeparam>
        /// <typeparam name="TInput1">The type of the input1.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of addition operator.</returns>
        public static TResult[] Addition<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "AdditionArrayValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp[i] + valInp);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp, T1 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the addition of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of addition operator.</returns>
        public static TResult[] Addition<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1[] operand2)
        {
            // checks the dimensions.
            if (operand1.Length != operand2.Length)
            {
                throw new OperatorException("The arrays must have the same lenght to apply +.");
            }

            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "AdditionArray.<" + type0 + ">.<" + type1 + ">.<"+ type2 +">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp1.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp1[i] + arrInp2[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp1, T1[] arrInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        #endregion

        #region Subtraction

        /// <summary>
        /// Computes the subtraction of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of subtraction operator.</returns>
        public static TResult Subtraction<TInput0, TInput1, TResult>(TInput0 operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "SubtractionValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T2 valOut = (T2)(valInp1 - valInp2);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp1, T1 valInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the subtraction of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of subtraction operator.</returns>
        public static TResult[] Subtraction<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "SubtractionArrayValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp[i] - valInp);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp, T1 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the subtraction of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of subtraction operator.</returns>
        public static TResult[] Subtraction<TInput0, TInput1, TResult>(TInput0 operand1, TInput1[] operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "SubtractionValueArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(valInp - arrInp[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp, T1[] arrInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the subtraction of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of subtraction operator.</returns>
        public static TResult[] Subtraction<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1[] operand2)
        {
            // checks the dimensions.
            if (operand1.Length != operand2.Length)
            {
                throw new Exception("The arrays must have the same lenght to apply +.");
            }

            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "SubtractionArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp1.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp1[i] - arrInp2[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp1, T1[] arrInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        #endregion

        #region Multiply

        /// <summary>
        /// Computes the multiply of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of multiply operator.</returns>
        public static TResult Multiply<TInput0, TInput1, TResult>(TInput0 operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "MultiplyValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T2 valOut = (T2)(valInp1 * valInp2);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp1, T1 valInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the multiply of two inputs.
        /// </summary>
        /// <typeparam name="TInput0">The type of the input0.</typeparam>
        /// <typeparam name="TInput1">The type of the input1.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of multiply operator.</returns>
        public static TResult[] Multiply<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "MultiplyArrayValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp[i] * valInp);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp, T1 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the multiply of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of multiply operator.</returns>
        public static TResult[] Multiply<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1[] operand2)
        {
            // checks the dimensions.
            if (operand1.Length != operand2.Length)
            {
                throw new Exception("The arrays must have the same lenght to apply +.");
            }

            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "MultiplyArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp1.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp1[i] * arrInp2[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "tin[] arrInp1, tout[] arrInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        #endregion

        #region Division

        /// <summary>
        /// Computes the division of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of division operator.</returns>
        public static TResult Division<TInput0, TInput1, TResult>(TInput0 operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "DivisionValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T2 valOut = (T2)(valInp1 / valInp2);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp1, T1 valInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the division of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of division operator.</returns>
        public static TResult[] Division<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "DivisionArrayValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp[i] / valInp);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp, T1 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the division of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of division operator.</returns>
        public static TResult[] Division<TInput0, TInput1, TResult>(TInput0 operand1, TInput1[] operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "DivisionValueArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(valInp / arrInp[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp, T1[] arrInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the division of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of division operator.</returns>
        public static TResult[] Division<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1[] operand2)
        {
            // checks the dimensions.
            if (operand1.Length != operand2.Length)
            {
                throw new Exception("The arrays must have the same lenght to apply +.");
            }

            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "DivisionArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp1.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp1[i] / arrInp2[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp1, T1[] arrInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        #endregion

        #region Modulus

        /// <summary>
        /// Computes the modulus of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of modulus operator.</returns>
        public static TResult Modulus<TInput0, TInput1, TResult>(TInput0 operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "ModulusValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            T2 valOut = (T2)(valInp1 % valInp2);
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp1, T1 valInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the modulus of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of modulus operator.</returns>
        public static TResult[] Modulus<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1 operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "ModulusArrayValue.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp[i] % valInp);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp, T1 valInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the modulus of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of modulus operator.</returns>
        public static TResult[] Modulus<TInput0, TInput1, TResult>(TInput0 operand1, TInput1[] operand2)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "ModulusValueArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(valInp % arrInp[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0 valInp, T1[] arrInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        /// <summary>
        /// Computes the modulus of two inputs.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand1">The operand1.</param>
        /// <param name="operand2">The operand2.</param>
        /// <returns>The result of modulus operator.</returns>
        public static TResult[] Modulus<TInput0, TInput1, TResult>(TInput0[] operand1, TInput1[] operand2)
        {
            // checks the dimensions.
            if (operand1.Length != operand2.Length)
            {
                throw new Exception("The arrays must have the same lenght to apply +.");
            }

            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput0).ToString();
            string type1 = typeof(TInput1).ToString();
            string type2 = typeof(TResult).ToString();
            string hashString = "DivisionArray.<" + type0 + ">.<" + type1 + ">.<" + type2 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp1.Length;
            T2[] arrOut = new T2[cnt];
            for(int i=0; i < cnt; i++)
            {
                arrOut[i] = (T2)(arrInp1[i] % arrInp2[i]);
            }
            return arrOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1, type2 }, "T0[] arrInp1, T2[] arrInp2", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult[])dynCode.Invoke(operand1, operand2);
        }

        #endregion

        /// <summary>
        /// Computes the sum of an array of data.
        /// </summary>
        /// <typeparam name="TInput">The type of the input.</typeparam>
        /// <typeparam name="TOutput">The type of the output.</typeparam>
        /// <param name="operand">The operand.</param>
        /// <returns>The sum value.</returns>
        public static TResult Sum<TInput, TResult>(TInput[] operand)
        {
            // Gets the corresponding dynamic code.
            string type0 = typeof(TInput).ToString();
            string type1 = typeof(TResult).ToString();
            string hashString = "SumArray.<" + type0 + ">.<" + type1 + ">";
            DynamicCode dynCode = Hash(hashString);

            // Creates a new instance of dynamic code.
            if (dynCode == null)
            {
                string code = @"
            int cnt = arrInp.Length;
            T1 valOut = default(T1);
            for(int i=0; i < cnt; i++)
            {
                valOut = (T1)(valOut + arrInp[i]);
            }
            return valOut;";

                dynCode = new DynamicCode();
                dynCode.Compile(new string[] { type0, type1 }, "T0[] arrInp", code);
                dynamicCodeHash.Add(hashString, dynCode);
            }

            // Computes.
            return (TResult)dynCode.Invoke(operand);
        }
    }
}
